package org.sdnstproject.interlayer.interlayerProxy;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AgentManager extends Thread{
	private static final Logger log = LoggerFactory.getLogger(AgentManager.class);
	private ServerSocket serverSocket;
	private int portNum;
	private Socket connected;
	private Agent controllerm;
	private Agent switchm;
	private BufferedReader hostReader;
	private BufferedWriter hostWriter;
	private Configuration config = Configuration.getInstance();
	public volatile boolean running = true;
	public volatile boolean start = false;
	public AtomicInteger readyAgent = new AtomicInteger(0);
	
    public AgentManager() {
    	this.portNum = Integer.parseInt(config.getManagerPort());
    	scpModule();
    }
    
    public void scpModule() {
    	try {
			Runtime.getRuntime().exec("scp "+config.getInterlayer_ROOT()+"/pyscript/switchAgent.py "+config.getSwitchSSH()+":~/");
			Runtime.getRuntime().exec("scp "+config.getInterlayer_ROOT()+"/pyscript/controllerAgent.py "+config.getControllerSSH()+":~/");
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
    
    @Override
    public void run() {
        log.info("Start Server socket");
        this.controllerm = new Agent(true);
        this.switchm = new Agent(false);
        Thread conThread = new Thread(controllerm);
        conThread.start();
        Thread swiThread = new Thread(switchm);
        swiThread.start();
        
        try {
        	serverSocket = new ServerSocket(portNum);
        	serverSocket.setReuseAddress(true);
        	if(serverSocket == null) {
        		log.info("serverSocket get failed.");
        		controllerm.stopSelf();
        		controllerm.stopSelf();
        		conThread.interrupt();
        		swiThread.interrupt();
        		return;
        	}else {
				log.info("serverSocket get success.");
			}
        	
            while (running && !Thread.currentThread().isInterrupted()) {
            	connected = serverSocket.accept();
            	BufferedReader inReader = new BufferedReader(new InputStreamReader(connected.getInputStream()));
            	BufferedWriter outWriter = new BufferedWriter(new OutputStreamWriter(connected.getOutputStream()));
            	String line = inReader.readLine();
            	if (line.contains("ControllerAgent")) {
            		controllerm.setIO(inReader, outWriter);
            		synchronized (controllerm) {
						controllerm.notify();
					}
            		log.info("ControllerAgent connected.");
            		readyAgent.getAndIncrement();
            		synchronized (this) {
						if(readyAgent.get() >= 2) {
							notify();
						}
					}
            	} else if(line.contains("SwitchAgent")) {
            		switchm.setIO(inReader, outWriter);
            		synchronized (switchm) {
            			switchm.notify();
					}
            		log.info("SwitchAgent connected.");
            		readyAgent.getAndIncrement();
            		synchronized (this) {
						if(readyAgent.get() >= 2) {
							notify();
						}
					}
                } else if(line.contains("HostAgent")) {
                	this.hostReader = inReader;
                	this.hostWriter = outWriter;
            		log.info("HostAgent connected.");
            		readyAgent.getAndIncrement();
                } else {
					log.info("AgentManager recv "+line);
					continue;
				}
            	outWriter.write("OK");
            	outWriter.flush();
            }
        } catch (Exception e) {
        	try {
				serverSocket.close();
				controllerm.stopSelf();
        		controllerm.stopSelf();
//        		conThread.interrupt();
//        		swiThread.interrupt();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
            e.printStackTrace();
        }
    }
    
    
    public Agent getControllerm() {
		return controllerm;
	}

	public void setControllerm(Agent controllerm) {
		this.controllerm = controllerm;
	}

	public Agent getSwitchm() {
		return switchm;
	}

	public void setSwitchm(Agent switchm) {
		this.switchm = switchm;
	}

	public boolean hostmWriter(String string) throws Exception {
		if(hostWriter == null) {
			log.error("host agent has not connected.");
			return false;
		}
		hostWriter.write(string);
		hostWriter.flush();
		return true;
	}

	public String hostmReader() throws Exception{
		String ret = "";
		char[] buf = new char[1024];
		while(hostReader.read(buf) != -1) {
			ret += new String(buf);
		}
		return ret;
	}
	
    
}
